#pragma once
#include "Common.hpp"
#include "Log.hpp"
#include "Channel.hpp"
#include "Time.hpp"
#include "Poll.hpp"

class EventLoop {
    private:
        using Functor = std::function<void()>;
        std::thread::id _thread_id;//线程ID
        int _event_fd;//eventfd唤醒IO事件监控有可能导致的阻塞
        std::unique_ptr<Channel> _event_channel;
        Poller _poller;//进行所有描述符的事件监控
        std::vector<Functor> _tasks;//任务池
        std::mutex _mutex;//实现任务池操作的线程安全
        TimerWheel _timer_wheel;//定时器模块
    public:
        //执行任务池中的所有任务
        void RunAllTask() {
            std::vector<Functor> functor;
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                _tasks.swap(functor);
            }
            for (auto &f : functor) {
                f();
            }
            return ;
        }
        static int CreateEventFd() {
            int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
            if (efd < 0) {
                LOG_ERROR("CREATE EVENTFD FAILED!!");
                abort();//让程序异常退出
            }
            return efd;
        }
        void ReadEventfd() {
            uint64_t res = 0;
            int ret = read(_event_fd, &res, sizeof(res));
            if (ret < 0) {
                //EINTR -- 被信号打断；   EAGAIN -- 表示无数据可读
                if (errno == EINTR || errno == EAGAIN) {
                    return;
                }
                LOG_ERROR("READ EVENTFD FAILED!");
                abort();
            }
            return ;
        }
        void WeakUpEventFd() {
            uint64_t val = 1;
            int ret = write(_event_fd, &val, sizeof(val));
            if (ret < 0) {
                if (errno == EINTR) {
                    return;
                }
                LOG_ERROR("READ EVENTFD FAILED!");
                abort();
            }
            return ;
        }
    public:
        EventLoop():_thread_id(std::this_thread::get_id()), 
                    _event_fd(CreateEventFd()), 
                    _event_channel(new Channel(this, _event_fd)),
                    _timer_wheel(this) {
            //给eventfd添加可读事件回调函数，读取eventfd事件通知次数
            _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventfd, this));
            //启动eventfd的读事件监控
            _event_channel->EnableRead();
        }
        //三步走--事件监控-》就绪事件处理-》执行任务
        void Start() {
            while(1) {
                //1. 事件监控， 
                std::vector<Channel *> actives;
                _poller.Poll(&actives);
                //2. 事件处理。 
                for (auto &channel : actives) {
                    channel->HandleEvent();
                }
                //3. 执行任务
                RunAllTask();
            }
        }
        //用于判断当前线程是否是EventLoop对应的线程；
        bool IsInLoop() {
            return (_thread_id == std::this_thread::get_id());
        }
        void AssertInLoop() {
            assert(_thread_id == std::this_thread::get_id());
        }
        //判断将要执行的任务是否处于当前线程中，如果是则执行，不是则压入队列。
        void RunInLoop(const Functor &cb) {
            if (IsInLoop()) {
                return cb();
            }
            return QueueInLoop(cb);
        }
        //将操作压入任务池
        void QueueInLoop(const Functor &cb) {
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                _tasks.push_back(cb);
            }
            //唤醒有可能因为没有事件就绪，而导致的epoll阻塞；
            //其实就是给eventfd写入一个数据，eventfd就会触发可读事件
            WeakUpEventFd();
        }
        //添加/修改描述符的事件监控
        void UpdateEvent(Channel *channel) { return _poller.UpdateEvent(channel); }
        //移除描述符的监控
        void RemoveEvent(Channel *channel) { return _poller.RemoveEvent(channel); }
        void AddTimer(uint64_t id, uint32_t delay, const TaskFunc &cb) { return _timer_wheel.AddTimer(id, delay, cb); }
        void RefreshTimer(uint64_t id) { return _timer_wheel.RefreshTimer(id); }
        void CancelTimer(uint64_t id) { return _timer_wheel.CancelTimer(id); }
        bool HasTimer(uint64_t id) { return _timer_wheel.HasTimer(id); }
};


class LoopThread{
private:
// 实例化 EventLoop 对象, 唤醒 _cond 上有可能阻塞的线程, 并且开始运行 EventLoop 模块的功能
    void ThreadEntry(){
        EventLoop loop; // 实例化 EventLoop 对象
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _loop = &loop; // 保存 EventLoop 对象指针, 不创建一个新的, 是希望 LoopThread 来管理其生命周期
            _cond.notify_all(); // 唤醒阻塞的线程
        }
        loop.Start(); // 循环运行
    }

public:
    // 创建线程, 设定线程入口函数
    LoopThread(): _loop(nullptr), _thread(std::thread(&LoopThread::ThreadEntry, this)){}

    // 返回 EventLoop 对象指针
    EventLoop* Loop() { 
        EventLoop *loop = nullptr;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _cond.wait(_lock, [&](){return _loop != nullptr;}); // loop 如果为 nullptr 则等待
            loop = _loop; // 获取 EventLoop 对象指针
        }
        return loop;
    }

private:
    EventLoop* _loop; // EventLoop 指针变量, 这个对象需要在线程内实例化
    std::thread _thread; // EventLoop 对应的线程对象

    // 用于实现 _loop 获取的同步关系, 避免线程创建但是 _loop 还没有初始化的情况
    std::mutex _mutex; // 互斥锁
    std::condition_variable _cond; // 条件变量
};


class LoopThreadPool{
public:
    LoopThreadPool(EventLoop *baseloop): _thread_cnt(0), _next_idx(0), _baseloop(baseloop){}

    // 设置线程数量
    void SetThreadCount(int cnt){
        _thread_cnt = cnt;
    }

    // 创建所有的从属线程
    void CreateThreads(){
        if(_thread_cnt > 0){
            _threads.resize(_thread_cnt); // 也可以用 reserve
            _loops.resize(_thread_cnt);
            for(int i = 0; i < _thread_cnt; ++i){
                _threads[i] = new LoopThread();
                _loops[i] = _threads[i]->Loop(); // 获取 EventLoop 对象指针
            }
        }
        return ;
    }

    // 获取下一个 Loop
    EventLoop* NextLoop(){
        if(_thread_cnt == 0){return _baseloop;}
        _next_idx = (_next_idx + 1) % _thread_cnt; // 轮询分配线程
        return _loops[_next_idx];
    }
    
private:    
    int _thread_cnt;                  // 从属线程数量
    int _next_idx;                 // 下一个待分配的 EventLoop 索引
    EventLoop* _baseloop;               // 主 EventLoop, 运行在主线程, 若从属线程为 0, 则所有操作都在 baseLoop 上进行
    std::vector<LoopThread*> _threads;   // 保存所有的 LoopThread 对象
    std::vector<EventLoop*> _loops;     // 从属线程数量 大于 0, 则从 _loops 中取出 EventLoop 进行操作, 否则操作 _baseloop
};


void TimerWheel::AddTimer(uint64_t id, uint32_t delay, const TaskFunc& cb){
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, delay, cb)); // 添加定时任务
}
// 2. 刷新/延迟 定时任务
void TimerWheel::RefreshTimer(uint64_t id){
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop, this, id)); // 添加定时任务
}
// 3. 取消定时任务
void TimerWheel::CancelTimer(uint64_t id) {
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCanceInLoop, this, id)); // 添加定时任务
}